package com.krystal.crawler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.core.var.Constants;
import com.krystal.bean.CovidBean;
import com.krystal.mapper.DataMapper;
import com.krystal.services.SpiderMsgService;
import com.krystal.util.HttpUtils;
import com.krystal.util.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @author Krystal1
 * @date 2021/4/25 -14:25
 * 该代码爬取自丁香园数据                                  接口稳定不需要更改地址,
 * 实现疫情数据爬取，完成covid19_2、covid19_3和covid19_4数据库表的数据爬取和更新
 */
@Component
@Slf4j
public class Covid19DateCrawlerMain {

    static DataMapper mapper;
    public static List<CovidBean> pCovidBeans;      //省份数据
    /**接口地址*/
    public static final String URL = "https://ncov.dxy.cn/ncovh5/view/pneumonia";

    //静态代码块初始化 避免资源浪费
    static {
        InputStream resourceAsStream;
        try {
            resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);
            mapper = sqlSession.getMapper(DataMapper.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @return Response
     */
    public SpiderMsgService.Response crawlOthers(){
        /**响应消息*/
        SpiderMsgService.Response response = new SpiderMsgService.Response();
        String datetime = TimeUtils.format(System.currentTimeMillis(), "yyyy-MM-dd");
        //判断covid19_4的数据是否需要更新 判断日期
        String sqlTime = mapper.selectDateTime();           //查询数据库中covid19_4的存储的时间数据
        //1.爬取指定页面
        String html = HttpUtils.getHtml(URL);
        //2.解析页面中的指定内容,即id为getAreaStat的标签中的全国疫情数据
        Document doc = Jsoup.parse(html);
        String text = doc.select("script[id=getAreaStat]").toString();
        //3.使用正则表达式获取json格式的疫情数据
        String pattern = "\\[(.*)\\]";              //定义正则规则
        Pattern reg = Pattern.compile(pattern);     //编译成正则对象
        Matcher matcher = reg.matcher(text);        //去text中进行匹配
        String jsonStr = "";
        if (matcher.find()) {                         //如果text中的内容和正则规则匹配上就取出来赋值给jsonStr变量
            jsonStr = matcher.group(0);
            log.info("json报文：{}",jsonStr);
        } else {
            log.info("no match");
            response.setIsUpdated("0");
            response.setReturnMsg("正则表达式：no match");
            return  response;
        }
        //4.对json数据进行更进一步的解析
        //将第一层Json（省份数据）解析为JavaBean
        pCovidBeans = JSON.parseArray(jsonStr, CovidBean.class);         //省份的
        int updateCount = 0;
        log.info("正在更新covid19_2、covid19_3和covid19_4表数据，请勿中断程序~");
        for (CovidBean pCovidBean : pCovidBeans) {          //pCovidBean 为省份
            //log.info(pCovidBean);
            //先设置时间字段
            pCovidBean.setDatetime(datetime);
            //这里可以将省的数据放入数据库了
            updateDataProvince(pCovidBean);             //更新省份表
            updateCount++;
            //如果省份是台湾、香港、澳门 需要插入到城市表中，其中省份短名和城市相同
            if (pCovidBean.getProvinceShortName().equals("台湾") || pCovidBean.getProvinceShortName().equals("澳门") || pCovidBean.getProvinceShortName().equals("香港")) {
                pCovidBean.setCityName(pCovidBean.getProvinceShortName());
                //初始化covid19_3中自治省的数据，调用一次不再调用初始化而是更新
                //insertInitCity(pCovidBean);
                updateDataCity(pCovidBean);
                updateCount++;
            }
            //获取cities
            String citysStr = pCovidBean.getCities();

            /*
             *关键  当台湾、澳门等省市无city信息的 应该跳过本次循环 否则会错误中断
             */
            if ("[]".equals(citysStr)){
                log.info("{}城市信息已经录入,跳过！",pCovidBean.getProvinceShortName());
                continue;
            }
            //5.将第二层json(城市数据)解析为JavaBean
            List<CovidBean> covidBeans = JSON.parseArray(citysStr, CovidBean.class);
            log.info("{}地区数据共{}条数据",pCovidBean.getProvinceShortName(), covidBeans.size());
            for (CovidBean bean : covidBeans) {                     //bean为城市
                bean.setDatetime(datetime);
                bean.setPid(pCovidBean.getLocationId());    //把省份的id作为城市的pid
                bean.setProvinceShortName(pCovidBean.getProvinceShortName());
                //insertInitCity(bean);         //调用方法 初始化city表(插入数据)
                updateInitImport(bean, datetime, sqlTime);             //初始化covid19_4表
                updateCount++;
                updateDataCity(bean);           //调用下面的方法 更新city表
                updateCount++;
            }

            //6.获取第一层json（省份数据）中的每一天的统计数据
            String statisticsDataUrl = pCovidBean.getStatisticsData();
            String statisticsDataStr = HttpUtils.getHtml(statisticsDataUrl);
            //获取statisticDataStr中的data字段对应的数据
            JSONObject jsonObject = JSON.parseObject(statisticsDataStr);
            String dataStr = jsonObject.getString("data");
            //将爬取解析出来的每一天的数据设置回省份pCovidBean中的statisticsData字段中（之前该字段只是一个URL）
            pCovidBean.setStatisticsData(dataStr);
            pCovidBean.setCities(null);

        }
        log.info("covid19_2、covid19_3和covid19_4表数据更新完毕~");
        log.info("数据更新完毕~");
        response.setIsUpdated("1");//更新成功
        response.setUpdateCount(updateCount + "");
        response.setReturnCode(Constants.SUCCESS_CODE);//000000
        response.setReturnMsg("本地数据插入成功!");

        return response;
    }


    /**
     * 测试类 已经弃用
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        String datetime = TimeUtils.format(System.currentTimeMillis(), "yyyy-MM-dd");
        String sqlTime = mapper.selectDateTime();           //查询数据库中covid19_4d的存储的时间数据
        //1.爬取指定页面
        String html = HttpUtils.getHtml("https://ncov.dxy.cn/ncovh5/view/pneumonia");
        //2.解析页面中的指定内容,即id为getAreaStat的标签中的全国疫情数据
        Document doc = Jsoup.parse(html);
        String text = doc.select("script[id=getAreaStat]").toString();
        //3.使用正则表达式获取json格式的疫情数据
        String pattern = "\\[(.*)\\]";              //定义正则规则
        Pattern reg = Pattern.compile(pattern);     //编译成正则对象
        Matcher matcher = reg.matcher(text);        //去text中进行匹配
        String jsonStr = "";
        if (matcher.find()) {                         //如果text中的内容和正则规则匹配上就取出来赋值给jsonStr变量
            jsonStr = matcher.group(0);
            log.info("json报文：{}",jsonStr);
        } else {
            log.info("no match");
        }
        //4.对json数据进行更进一步的解析
        //将第一层Json（省份数据）解析为JavaBean
        pCovidBeans = JSON.parseArray(jsonStr, CovidBean.class);         //省份的
        int updateCount = 0;
        for (CovidBean pCovidBean : pCovidBeans) {          //pCovidBean 为省份
            //log.info(pCovidBean);
            //先设置时间字段
            pCovidBean.setDatetime(datetime);
            //这里可以将省的数据放入数据库了
            updateDataProvince(pCovidBean);             //更新省份表
            //如果省份是台湾、香港、澳门 需要插入到城市表中，其中省份短名和城市相同
            if (pCovidBean.getProvinceShortName().equals("台湾") || pCovidBean.getProvinceShortName().equals("澳门") || pCovidBean.getProvinceShortName().equals("香港")) {
                pCovidBean.setCityName(pCovidBean.getProvinceShortName());
                //初始化covid19_3中自治省的数据，调用一次不再调用初始化而是更新
                //insertInitCity(pCovidBean);
                updateDataCity(pCovidBean );
            }
            //获取cities
            String citysStr = pCovidBean.getCities();
            //5.将第二层json(城市数据)解析为JavaBean
            List<CovidBean> covidBeans = JSON.parseArray(citysStr, CovidBean.class);
            for (CovidBean bean : covidBeans) {                     //bean为城市
                bean.setDatetime(datetime);
                bean.setPid(pCovidBean.getLocationId());    //把省份的id作为城市的pid
                bean.setProvinceShortName(pCovidBean.getProvinceShortName());
                //insertInitCity(bean);         //调用方法 初始化city表(插入数据)
                updateInitImport(bean, datetime, sqlTime);             //初始化covid19_4表
                updateDataCity(bean);           //调用下面的方法 更新city表
            }
            //6.获取第一层json（省份数据）中的每一天的统计数据
            String statisticsDataUrl = pCovidBean.getStatisticsData();
            String statisticsDataStr = HttpUtils.getHtml(statisticsDataUrl);
            //获取statisticDataStr中的data字段对应的数据
            JSONObject jsonObject = JSON.parseObject(statisticsDataStr);
            String dataStr = jsonObject.getString("data");
            //将爬取解析出来的每一天的数据设置回省份pCovidBean中的statisticsData字段中（之前该字段只是一个URL）
            pCovidBean.setStatisticsData(dataStr);
            pCovidBean.setCities(null);
        }
    }

    //初始化covid_2数据库表  (初次需要调用)后续不再调用
    public static void insertInitProvince(CovidBean covidBean) {
        mapper.insertInit(covidBean);
    }

    //初始化covid19_3数据库  后续不再调用
    public static void insertInitCity(CovidBean covidBean) {
        mapper.insertInitCity(covidBean);
    }

    //更新covid19_4数据库表，境外输入, 在城市那个遍历里面调用 (如果数据库的最后一条数据的时间等于今天的时间，则更新，否则清空表，增加)
    public static void updateInitImport(CovidBean covidBean, String datetime, String sqlTime) {
        //如果datetime==sqlTime 则是更新数据库中的数据
        if (covidBean.getCityName().equals("境外输入") && datetime.equals(sqlTime)) {
            mapper.updateDataImport(covidBean);
        } else if (covidBean.getCityName().equals("境外输入") && !datetime.equals(sqlTime)) {
            mapper.insertInitImport(covidBean);
        }

    }

    //更新covid_2数据库表
    public static void updateDataProvince(CovidBean covidBean) {
        mapper.updateDataProvince(covidBean);
    }

    //更新covid_3数据库表
    public static void updateDataCity(CovidBean covidBean) {
        mapper.updateDataCity(covidBean);
    }
}
